﻿#include "C3fdRenderWindow.h"
#include "ui_C3fdRenderWindow.h"
#include "MainWindow/MainWindow.h"
#include <QSplitter>
#include <vtkRenderWindow.h>
#include <vtkDataSetMapper.h>
#include <vtkActor.h>
#include <vtkAxesActor.h>
#include <vtkTextActor.h>
#include <vtkTextProperty.h>
#include <vtkProperty.h>
#include <vtkTextRepresentation.h>
#include "C3fdTecplotAsciiFileReader.h"
#include "Settings/GraphOption.h"
#include "Settings/BusAPI.h"
#include <QFileInfo>
#include <QDebug>
#include "C3fdMonitorDatFileReader.h"
#include <vtkStructuredGrid.h>
#include <vtkCellData.h>
#include <vtkPointData.h>
#include <vtkDoubleArray.h>
#include <QHash>
#include <vtkCellDataToPointData.h>
#include <QFile>
#include <QTextStream>
#include <QPixmap>
#include <IVtkTools_ShapeDataSource.hxx>
#include <vtkPolyDataMapper.h>
#include <TColgp_Array1OfPnt.hxx>
#include <GeomAPI_PointsToBSpline.hxx>
#include <BRepBuilderAPI_MakeEdge.hxx>
#include <BRep_Builder.hxx>
#include <Geom_BSplineCurve.hxx>
#include <gp_Ax1.hxx>
#include <BRepPrimAPI_MakeRevol.hxx>
#include <BRepOffsetAPI_ThruSections.hxx>
#include <BRepBuilderAPI_MakeWire.hxx>
#include <BRepBuilderAPI_Transform.hxx>
#include <GeomAPI_Interpolate.hxx>
#include <gp_Trsf.hxx>
#include <TopoDS_Compound.hxx>
#include "Common/C3fdProject.h"
#include <QMessageBox>
#include <vtkPolyDataWriter.h>
#include <vtkStructuredGridWriter.h>
#include <vtkStructuredGridReader.h>
#include <vtkCamera.h>
#include <QDir>
#include <QDateTime>
#include <vtkPolyDataReader.h>
#include "ModuleBase/ThreadControl.h"
#include "C3fdGeomTurboFileReader.h"
#include "Common/C3fdMd5.h"

namespace MainWidget
{
	C3fdRenderWindow::C3fdRenderWindow(GUI::MainWindow *mw)
		: m_Ui(new Ui::C3fdRenderWindow), m_MainWindow(mw)
	{
		m_Ui->setupUi(this);
		connect(mw, SIGNAL(updateC3fdCaseSig()), this, SLOT(renderC3fdCacheSlot()));
		connect(this, SIGNAL(closed()), mw, SIGNAL(closeC3fdWindowSig()));
		connect(mw, SIGNAL(postSaveImageSig(QString, QString, int)), this, SLOT(postSaveImageSlot(QString, QString, int)));
		connect(this, SIGNAL(updateRowTreeSig()), mw, SIGNAL(updateC3fdRowTreeSig()));
		connect(mw, SIGNAL(updateGeomDisplayStatus(QString, bool)), this, SLOT(updateGeomDisplayStatusSlot(QString, bool)));
		connect(mw, SIGNAL(changeControlTab(QString)), this, SLOT(changeControlTabSlot(QString)));

		this->setWindowTitle(tr("C3FD Window"));

		m_Layout = new QGridLayout(this);
		m_Layout->setSpacing(0);
		m_Layout->setMargin(0);

		initGeomRenderWidget();
	}

	C3fdRenderWindow::~C3fdRenderWindow()
	{
		delete m_Ui;
		emit closed();
	}

	void C3fdRenderWindow::renderC3fdCacheSlot()
	{
		auto *currentCase = Common::C3fdProject::instance()->getCurrentCase();
		if (currentCase == nullptr)
		{
			return;
		}
		QDir cacheDir(QString("%1").arg(currentCase->getWorkDir() + Common::C3fdProject::instance()->getCacheDir() + QDir::separator()));
		// 缓存目录不存在，重新读取文件
		if (!cacheDir.exists())
		{
			renderC3fdGeomCache();
			return;
		}
		auto geomFileList = cacheDir.entryInfoList({ "geom_*.vtk" }, QDir::Files, QDir::Time);
		// 缓存文件不存在，重新读取文件
		if (geomFileList.isEmpty())
		{
			renderC3fdGeomCache();
			return;
		}

		Setting::GraphOption *option = Setting::BusAPI::instance()->getGraphOption();
		QColor geomcolor = option->getGeometrySurfaceColor();
		QColor meshEdgecolor = option->getMeshEdgeColor();
		// 几何
		if (initGeomRenderWidget(true))
		{
			auto renderer = m_GeomRenderWidget->getRenderer();
			// 读取缓存文件
			for (auto geomFile : geomFileList)
			{
				vtkNew<vtkPolyDataReader> reader;
				reader->SetFileName(geomFile.absoluteFilePath().toStdString().c_str());
				reader->Update();
				m_GeomRenderWidget->addPolyData(reader->GetOutput(), geomcolor);
			}
			m_GeomRenderWidget->fitView();
			emit updateRowTreeSig();
		}

		// 网格
		if (initMeshRenderWidget(true)) {
			// mesh_Omesh_3d_*.vtk
			// mesh_Omesh_s2_*.vtk
			// mesh_Omesh_b2b_hub_*.vtk
			// mesh_Omesh_b2b_mid_*.vtk
			// mesh_Omesh_b2b_tip_*.vtk

			QStringList meshFiles = {
				"mesh_Omesh_3d_*.vtk",
				"mesh_Omesh_s2_*.vtk",
				"mesh_Omesh_b2b_hub_*.vtk",
				"mesh_Omesh_b2b_mid_*.vtk",
				"mesh_Omesh_b2b_tip_*.vtk"
			};

			for (int i = 0; i < 5; ++i) {
				int lastPos = meshFiles.at(i).lastIndexOf("_");
				QString title = meshFiles.at(i).mid(5, lastPos - 5);
				auto meshFileList = cacheDir.entryInfoList({ meshFiles.at(i) }, QDir::Files, QDir::Time);
				// 缓存文件不存在，重新读取文件
				if (geomFileList.isEmpty())
				{
					break;
				}
				for (auto vtkFile : meshFileList) {
					vtkNew<vtkStructuredGridReader> reader;
					reader->SetFileName(vtkFile.absoluteFilePath().toStdString().c_str());
					reader->Update();
					//m_GeomRenderWidget->addStructuredGrid(reader->GetOutput(), meshEdgecolor);

					vtkNew<vtkDataSetMapper> edgeMapper;
					edgeMapper->SetInputData(reader->GetOutput());
					edgeMapper->SetScalarModeToUseCellData();
					vtkNew<vtkActor> edgeActor;
					edgeActor->SetMapper(edgeMapper);
					edgeActor->GetProperty()->SetRepresentationToWireframe();
					edgeActor->GetProperty()->SetEdgeColor(meshEdgecolor.redF(), meshEdgecolor.greenF(), meshEdgecolor.blueF());

					m_MeshRenderWidgets.at(i)->getRenderer()->AddActor(edgeActor);

					m_MeshRenderWidgets.at(i)->addTitle(title);

				}
				m_MeshRenderWidgets.at(i)->fitView();
			}
		}

		// 监控曲线
		if (initMonitorChartWidget(true)) {
			auto project = Common::C3fdProject::instance();
			auto wcs = currentCase->getWorkConditions();
			if (wcs.size() > 0) {
				QString firstWCMonitorFile = QString("%1%2%3%4%5%6%7%8").arg(project->getCurrentProjectDir())
					.arg(project->getWorkingConditionDirName()).arg(QDir::separator())
					.arg(wcs.value(wcs.keys().at(0))->getName()).arg(QDir::separator())
					.arg(project->getSolverOutputDirName()).arg(QDir::separator())
					.arg(project->getSolverMonitorFileName());
				QFile file(firstWCMonitorFile);
				if (file.exists()) {
					renderC3fdMonitorCurve(firstWCMonitorFile);
				}
			}

		}

		// 后处理
		if (initPostRendererWidget(true)) {

		}
	}

	void C3fdRenderWindow::finishRenderGeomTurboFileSlot()
	{
		if (m_GeomRenderWidget != nullptr)
		{
			m_GeomRenderWidget->fitView();
		}
		if (!m_ReadFromCache)
		{
			auto *currentCase = Common::C3fdProject::instance()->getCurrentCase();
			if (currentCase != nullptr)
			{
				auto geoms = currentCase->getGeomTurboFiles();
				if (geoms.empty())
				{
					return;
				}
				bool has = false;
				// currentCase->clearBladeRow();
				for (auto *geom : geoms)
				{
					has = false;
					for (auto eRow : currentCase->getBladeRows())
					{
						if (geom->getFileName() == eRow->getGeomFileName())
						{
							has = true;
							break;
						}
					}
					if (!has)
					{
						auto *row = new Common::BladeRow;
						row->setRowNum(geom->getRowNum());
						row->setBladeNum(geom->getNumOfBlades());
						row->setGeomFileName(geom->getFileName());
						currentCase->addBladeRow(row);
					}
				}
			}
		}
		emit updateRowTreeSig();
	}

	void C3fdRenderWindow::updateGeomDisplayStatusSlot(QString name, bool isShow)
	{
		if (m_GeomRenderWidget == nullptr)
		{
			return;
		}
		auto actors = m_GeomRenderWidget->getRenderer()->GetActors();

		vtkCollectionSimpleIterator actorsIt;
		actors->InitTraversal(actorsIt);
		vtkActor *actor = nullptr;
		while (actor = actors->GetNextActor(actorsIt))
		{
			if (actor->GetObjectName() == name.toStdString())
			{
				actor->SetVisibility(isShow);
				break;
			}
		}
		m_GeomRenderWidget->refreshRender();
	}

	void C3fdRenderWindow::changeControlTabSlot(QString tab)
	{
		if (tab == "geom")
		{
			initGeomRenderWidget(false);
		}
		else if (tab == "mesh")
		{
			initMeshRenderWidget(false);
		}
		else if (tab == "analysis")
		{
			initMonitorChartWidget(false);
		}
		else if (tab == "post")
		{
			initPostRendererWidget(false);
		}
	}

	void C3fdRenderWindow::renderC3fdGeomCache()
	{
		if (m_GeomRenderWidget == nullptr && !initGeomRenderWidget())
		{
			QMessageBox::critical(this, tr("Error Info"), tr("Failed to initialize the render window"));
			return;
		}

		QStringList files;
		auto *currentCase = Common::C3fdProject::instance()->getCurrentCase();
		if (currentCase != nullptr)
		{
			auto geomFiles = currentCase->getGeomTurboFiles();
			for (auto geomFile : geomFiles)
			{
				auto geom = currentCase->getWorkDir() + Common::C3fdProject::instance()->getMeshDirName() + QDir::separator() + geomFile->getFileName();
				files << geom;
			}

			// currentCase->clearBladeRow();
			currentCase->clearGeomTurboFiles();
		}

		if (files.size() > 0)
		{
			renderGeomTurboFile(m_GeomRenderWidget->getRenderer(), files, true);
		}
		emit updateRowTreeSig();
	}

	void C3fdRenderWindow::renderC3fdGeom(const QStringList &files, bool showHubAndShroud)
	{
		if (m_GeomRenderWidget == nullptr && !initGeomRenderWidget())
		{
			QMessageBox::critical(this, tr("Error Info"), tr("Failed to initialize the render window"));
			return;
		}

		renderGeomTurboFile(m_GeomRenderWidget->getRenderer(), files, showHubAndShroud);

		auto *currentCase = Common::C3fdProject::instance()->getCurrentCase();
		if (currentCase != nullptr)
		{
			for (auto file : files)
			{
				QFileInfo fileInfo(file);
				QFile::copy(file, currentCase->getWorkDir() + Common::C3fdProject::instance()->getMeshDirName() + QDir::separator() + fileInfo.fileName());
			}
		}
	}

	void C3fdRenderWindow::renderC3fdMesh(QStringList files)
	{
		QString path = Common::C3fdProject::instance()->getCurrentProjectDir() + Common::C3fdProject::instance()->getCacheDir() + QDir::separator();

		if (files.size() != 5 || !initMeshRenderWidget())
		{
			QMessageBox::critical(this, tr("Error Info"), tr("Failed to initialize the render window"));
			return;
		}

		Setting::GraphOption *option = Setting::BusAPI::instance()->getGraphOption();
		QColor meshEdgecolor = option->getMeshEdgeColor();
		QColor meshFaceColor = option->getMeshFaceColor();

		C3fdTecplotAsciiFileReader reader;
		for (int i = 0; i < 5; i++)
		{
			vtkSmartPointer<vtkRenderer> renderer = m_MeshRenderWidgets.at(i)->getRenderer();

			auto *tecDatObject = reader.parse(files.at(i));
			int zoneId = 0;
			for (auto *zone : tecDatObject->getZones())
			{
				vtkNew<vtkStructuredGrid> grid;
				vtkNew<vtkPoints> points;

				auto zoneData = zone->getDatas();
				for (auto point : zoneData)
				{
					if (zone->is3DPoint())
					{
						points->InsertNextPoint(point.at(0), point.at(1), point.at(2));
					}
					else
					{
						points->InsertNextPoint(point.at(0), point.at(1), 0);
					}
				}

				int dimX = zone->getDimI();
				int dimY = zone->getDimJ();
				int dimZ = zone->getDimK();
				if (dimX * dimY * dimZ == points->GetNumberOfPoints())
				{
					grid->SetDimensions(dimX, dimY, dimZ);
					grid->SetPoints(points);
				}
				else
				{
					qDebug() << "Error dim, dimX * dimY * dimZ != " << points->GetNumberOfPoints() << "!";
					return;
				}

				vtkNew<vtkDataSetMapper> edgeMapper;
				edgeMapper->SetInputData(grid);
				edgeMapper->SetScalarModeToUseCellData();
				vtkNew<vtkActor> edgeActor;
				edgeActor->SetMapper(edgeMapper);
				edgeActor->GetProperty()->SetRepresentationToWireframe();
				edgeActor->GetProperty()->SetColor(meshFaceColor.redF(), meshFaceColor.greenF(), meshFaceColor.blueF());
				edgeActor->GetProperty()->SetEdgeColor(meshEdgecolor.redF(), meshEdgecolor.greenF(), meshEdgecolor.blueF());

				renderer->AddActor(edgeActor);

				/*vtkNew<vtkDataSetMapper> faceMapper;
				faceMapper->SetInputData(grid);
				faceMapper->SetScalarModeToUseCellData();
				vtkNew<vtkActor> faceActor;
				faceActor->SetMapper(faceMapper);
				faceActor->GetProperty()->SetRepresentationToSurface();
				faceActor->GetProperty()->SetColor(meshFaceColor.redF(), meshFaceColor.greenF(), meshFaceColor.blueF());
				faceActor->GetProperty()->SetEdgeColor(meshEdgecolor.redF(), meshEdgecolor.greenF(), meshEdgecolor.blueF());
				renderer->AddActor(faceActor);*/

				QFileInfo fileInfo(files.at(i));
				m_MeshRenderWidgets.at(i)->addTitle(fileInfo.baseName());
				// 缓存网格模型
				vtkNew<vtkStructuredGridWriter> writer;
				writer->SetInputData(grid);
				writer->SetFileTypeToBinary();
				writer->SetFileName(QString("%1mesh_%2_%3.vtk").arg(path).arg(fileInfo.completeBaseName()).arg(++zoneId).toStdString().c_str());
				writer->Write();
			}

			m_MeshRenderWidgets.at(i)->fitView();
		}
	}

	void C3fdRenderWindow::renderC3fdPerformCurve(QList<QList<double>> totalData, QList<QList<double>> perStageData)
	{
		if (!initPerformChartWidget())
		{
			QMessageBox::critical(this, tr("Error Info"), tr("Failed to initialize the render window"));
			return;
		}

		QList<QVector<double>> rtp = {};
		QList<QVector<double>> effis = {};
		QList<QVector<double>> rtpStage = {};
		QList<QVector<double>> effisStage = {};

		auto *currentCase = Common::C3fdProject::instance()->getCurrentCase();

		QList<Common::PerformanceData> totalPData = {};
		QList<Common::PerformanceData> perStagePData = {};
		for (auto data : totalData)
		{
			if (data.size() == 3)
			{
				rtp.push_back({ data.at(0), data.at(1) });
				effis.push_back({ data.at(0), data.at(2) });

				Common::PerformanceData pData;
				pData.inletFlow = data.at(0);
				pData.pressureRatio = data.at(1);
				pData.efficiency = data.at(2);
				totalPData.push_back(pData);
			}
		}

		for (auto data : perStageData)
		{
			if (data.size() == 3)
			{
				rtpStage.push_back({ data.at(0), data.at(1) });
				effisStage.push_back({ data.at(0), data.at(2) });

				Common::PerformanceData pData;
				pData.inletFlow = data.at(0);
				pData.pressureRatio = data.at(1);
				pData.efficiency = data.at(2);
				perStagePData.push_back(pData);
			}
		}

		if (currentCase != nullptr)
		{
			auto wcs = currentCase->getWorkConditions();
			if (wcs.size() > 0)
			{
				auto *wc = wcs.value(wcs.keys().at(0));
				if (wc != nullptr)
				{
					double speed = wc->getRotationSpeed();
					auto *reportData = currentCase->getReportData();
					if (reportData != nullptr)
					{
						reportData->addPerformanceData(tr("Total Performance Parameter"), speed, totalPData);
						reportData->addPerformanceData(tr("Per Stage Performance Parameter"), speed, perStagePData);
					}
				}
			}
		}

		m_PerformCurveWidgets.at(0)->setData(rtp);
		m_PerformCurveWidgets.at(1)->setData(effis);
		m_PerformCurveWidgets.at(2)->setData(rtpStage);
		m_PerformCurveWidgets.at(3)->setData(effisStage);
	}

	void C3fdRenderWindow::renderC3fdMonitorCurve(QString file)
	{
		C3fdMonitorDatFileReader reader(file);
		auto titles = reader.getTitles();
		if (titles.size() < 1)
		{
			return;
		}

		if ((m_MonitorCurveWidget == nullptr) && !initMonitorChartWidget())
		{
			QMessageBox::critical(this, tr("Error Info"), tr("Failed to initialize the render window"));
			return;
		}

		m_MonitorCurveWidget->setData(reader.getValues());
	}

	void C3fdRenderWindow::renderC3fdPostData(QStringList files, QStringList types)
	{
		int size = files.size();
		if (size > 6 || size != types.size())
		{
			return;
		}

		if (!initPostRendererWidget())
		{
			QMessageBox::critical(this, tr("Error Info"), tr("Failed to initialize the render window"));
			return;
		}

		if (!renderPostFile(files, types))
		{
			return;
		}
	}

	void C3fdRenderWindow::setView(QString view)
	{
		switch (m_CurrentRenderType)
		{
		case RenderType::GeomRender:
			m_GeomRenderWidget->setView(view);
			break;
		case RenderType::MeshRender:
			for (auto *widget : m_MeshRenderWidgets)
			{
				widget->setView(view);
			}
			break;
		case RenderType::PostRender:
			for (auto widget : m_PostRenderWidgets)
			{
				auto *w = dynamic_cast<C3fdRenderWidget *>(widget.second);
				if (w != nullptr)
				{
					w->setView(view);
				}
			}
			break;
		default:
			break;
		}
	}

	bool C3fdRenderWindow::save()
	{

		auto *currentCase = Common::C3fdProject::instance()->getCurrentCase();
		if (currentCase == nullptr)
		{
			return false;
		}

		// 保存算例

		currentCase->save();
		return true;
	}

	void C3fdRenderWindow::renderGeomTurboFile(vtkSmartPointer<vtkRenderer> renderer, const QStringList &files, bool showHubAndShroud)
	{
		auto geomTurboReader = new C3fdGeomTurboFileReader(m_MainWindow, files, showHubAndShroud);
		geomTurboReader->setRenderer(renderer);
		connect(geomTurboReader, SIGNAL(finishRead()), this, SLOT(finishRenderGeomTurboFileSlot()));
		ModuleBase::ThreadControl *tc = new ModuleBase::ThreadControl(geomTurboReader);
		emit tc->threadStart();
	}

	bool C3fdRenderWindow::renderPostFile(const QStringList &files, const QStringList &types)
	{
		Setting::GraphOption *option = Setting::BusAPI::instance()->getGraphOption();
		QColor topcolor = option->getBackgroundTopColor();
		QColor bottomcolor = option->getBackgroundBottomColor();
		QColor meshEdgecolor = option->getMeshEdgeColor();

		int i = 0;
		for (const auto &t : types)
		{
			if (t.toLower() == "vtk")
			{
				C3fdTecplotAsciiFileReader reader;
				auto *obj = reader.parse(files.at(i));
				if (obj == nullptr)
				{
					return false;
				}

				QFileInfo fileInfo(files.at(i));

				int zoneId = 0;
				for (auto *zone : obj->getZones())
				{
					vtkNew<vtkStructuredGrid> grid;
					vtkNew<vtkPoints> points;
					QHash<int, QVector<double>> vars = {};

					int dimX = zone->getDimI();
					int dimY = zone->getDimJ();
					int dimZ = zone->getDimK();

					auto zoneData = zone->getDatas();

					if (zone->getPackingMethod() == PackingMethod::BLOCK)
					{
						auto locs = zone->getValLocations();
						for (auto k : locs.keys())
						{
							QVector<double> val = {};
							vars.insert(k, val);
						}

						qreal x, y, z;
						int numOfCell = zone->getNumOfCell();
						for (int i = 0; i < dimX * dimY * dimZ; i++)
						{
							x = zoneData.at(0).at(i);
							y = zoneData.at(1).at(i);
							if (zone->is3DPoint())
							{
								z = zoneData.at(2).at(i);
								points->InsertNextPoint(x, y, z);
							}
							else
							{
								points->InsertNextPoint(x, y, 0);
							}

							QHash<int, QVector<qreal>>::iterator it = vars.begin();
							while (it != vars.end() && i < numOfCell)
							{
								auto b = it.key();
								it.value().push_back(zoneData.at(it.key() - 1).at(i));
								++it;
							}
						}
					}
					else
					{
						int varStartOrder = 3;
						if (zone->is3DPoint())
						{
							++varStartOrder;
						}
						int maxOrder = obj->getVariables().size();

						for (int i = varStartOrder; i <= maxOrder; i++)
						{
							QVector<double> val = {};
							vars.insert(i, val);
						}

						for (const auto &point : zoneData)
						{
							maxOrder = point.size();
							if (zone->is3DPoint())
							{
								points->InsertNextPoint(point.at(0), point.at(1), point.at(2));
							}
							else
							{
								points->InsertNextPoint(point.at(0), point.at(1), 0);
							}

							QHash<int, QVector<qreal>>::iterator it = vars.begin();
							while (it != vars.end())
							{
								it.value().push_back(point.at(it.key() - 1));
								++it;
							}
						}
					}

					if (dimX * dimY * dimZ == points->GetNumberOfPoints())
					{
						grid->SetDimensions(dimX, dimY, dimZ);
						grid->SetPoints(points);

						for (auto k : vars.keys())
						{
							if (zone->getPackingMethod() == PackingMethod::BLOCK)
							{
								auto locs = zone->getValLocations();
								if (locs.value(k) == ValLocation::CELLCENTERED)
								{

									if (grid->GetNumberOfCells() == vars.value(k).size())
									{
										vtkNew<vtkDoubleArray> var;
										var->SetNumberOfComponents(1);
										var->SetName(obj->getVariables().at(k - 1).toStdString().c_str());
										for (int i = 0; i < vars.value(k).size(); i++)
										{
											double v = vars.value(k).at(i);
											var->InsertNextTuple1(v);
										}
										grid->GetCellData()->AddArray(var);
									}
								}
								else if (locs.value(k) == ValLocation::NODAL)
								{

									if (grid->GetNumberOfPoints() == vars.value(k).size())
									{
										vtkNew<vtkDoubleArray> var;
										var->SetNumberOfComponents(1);
										var->SetName(obj->getVariables().at(k - 1).toStdString().c_str());
										for (int i = 0; i < vars.value(k).size(); i++)
										{
											double v = vars.value(k).at(i);
											var->InsertNextTuple1(v);
										}
										grid->GetPointData()->AddArray(var);
									}
								}
							}
							else
							{
								if (grid->GetNumberOfPoints() == vars.value(k).size())
								{
									vtkNew<vtkDoubleArray> var;
									var->SetNumberOfComponents(1);
									var->SetName(obj->getVariables().at(k - 1).toStdString().c_str());
									for (int i = 0; i < vars.value(k).size(); i++)
									{
										double v = vars.value(k).at(i);
										var->InsertNextTuple1(v);
									}
									grid->GetPointData()->AddArray(var);
								}
							}
						}
					}
					else
					{
						qDebug() << "Error dim, dimX * dimY * dimZ != " << points->GetNumberOfPoints() << "!";
						return false;
					}
					// 缓存后处理模型
					QString path = Common::C3fdProject::instance()->getCurrentProjectDir() + Common::C3fdProject::instance()->getCacheDir() + QDir::separator();
					vtkNew<vtkStructuredGridWriter> writer;
					writer->SetInputData(grid);
					writer->SetFileTypeToBinary();
					writer->SetFileName(QString("%1post_%2_%3.vtk").arg(path).arg(fileInfo.completeBaseName()).arg(++zoneId).toStdString().c_str());
					writer->Write();

					auto *vtkWidget = dynamic_cast<C3fdRenderWidget *>(m_PostRenderWidgets.at(i).second);
					if (vtkWidget != nullptr)
					{
						vtkWidget->addStructuredGrid(grid, meshEdgecolor);
						vtkWidget->setTitle(fileInfo.baseName());
						vtkWidget->addAxes();
						vtkWidget->fitView();
					}
				}
			}
			else if (t.toLower() == "qwt")
			{
				C3fdMonitorDatFileReader reader(files.at(i));
				auto *chartWidget = dynamic_cast<C3fdChartWidget *>(m_PostRenderWidgets.at(i).second);
				if (chartWidget != nullptr)
				{
					chartWidget->setData(reader.getValues());
				}
			}
			else
			{
				return false;
			}
			++i;
		}

		return true;
	}

	QString C3fdRenderWindow::translate(QString name) const
	{
		if (name.endsWith("PressureRatio_Stage"))
		{
			return tr("Stage_MassFlow-PressureRatio");
		}
		else if (name.endsWith("PressureRatio"))
		{
			return tr("MassFlow-PressureRatio");
		}
		else if (name.endsWith("Stage_Efficiency"))
		{
			return tr("Stage_MassFlow-Efficiency");
		}
		else if (name.endsWith("Efficiency"))
		{
			return tr("MassFlow-Efficiency");
		}
		else
		{
			return name;
		}
	}

	void C3fdRenderWindow::postSaveImageSlot(const QString &path, QString wcName, int height)
	{
		if (height > 999 || height < 1)
		{
			return;
		}
		auto strHeight = height < 10 ? QString("0%1").arg(QString::number(height)) : QString::number(height);
		auto *currentCase = Common::C3fdProject::instance()->getCurrentCase();
		QString time = QString("%1").arg(QDateTime::currentMSecsSinceEpoch());
		// 后处理保存图片
		if (m_CurrentRenderType == RenderType::PostRender)
		{
			for (auto w : m_PostRenderWidgets)
			{
				QString imgFile = "";
				QString name = "charact";
				if (w.first == "vtk")
				{
					auto *wid = qobject_cast<C3fdRenderWidget *>(w.second);
					name = wid->getTitle();

					QString locName = "Undefined";
					if (name.startsWith("bldsfparam"))
					{
						locName = "blade";
					}
					else if (name.startsWith("vs2ave"))
					{
						locName = "S2";
					}
					else if (name.startsWith("s1flow"))
					{
						locName = "S1";
					}
					auto shadeField = wid->getShadeField();
					QString saveName = "";
					if (!shadeField.isEmpty()) {
						saveName = QString("%1_%2_%3_R%4").arg(wcName).arg(locName).arg(wid->getShadeField()).arg(strHeight);
					}
					else {
						saveName = QString("%1_%2_R%3").arg(wcName).arg(locName).arg(strHeight);
					}
					wid->saveImage(QString("%1/%2.jpg").arg(path).arg(saveName));
					if (currentCase != nullptr)
					{
						// 保存图片用于生成报告
						imgFile = QString("%1temp/Post-%2_%3.jpg").arg(currentCase->getWorkDir()).arg(saveName).arg(time);
						wid->saveImage(imgFile, 560, 280, Common::AspectRatioMode::KeepWidth, 100);
					}
				}
				else if (w.first == "qwt")
				{
					auto *wid = dynamic_cast<C3fdChartWidget *>(w.second);
					name = wid->getSeriesTitles().join("-");
					auto saveName = QString("%1_BladeS1_SPRE_R%2").arg(wcName).arg(strHeight);
					wid->saveImage(QString("%1/%2.jpg").arg(path).arg(saveName));
					if (currentCase != nullptr)
					{
						// 保存图片用于生成报告
						imgFile = QString("%1temp/Post-%2%3.jpg").arg(currentCase->getWorkDir()).arg(saveName).arg(time);
						wid->saveImage(imgFile, 560, 280, Common::AspectRatioMode::KeepWidth, 100);
					}
				}
				// QPixmap pixmap = w.second->grab();
				// pixmap.save(QString("%1/%2%3%4.jpg").arg(path).arg(name).arg(height).arg(time), "JPG");

				if (currentCase != nullptr)
				{
					QString caseDir = currentCase->getWorkDir();

					auto imgTitle = name;
					if (name.startsWith("bldsfparam"))
					{
						imgTitle = QString(tr("YPlus Contour(%1)")).arg(wcName);
					}
					else if (name.startsWith("vs2ave"))
					{
						imgTitle = QString(tr("Circum Avarage Mach Contour(%1)")).arg(wcName);
					}
					else if (name.startsWith("bldspr"))
					{
						imgTitle = QString(tr("%1% Static Pressure Distribution Of Wall(%2)"))
							.arg(strHeight.endsWith("0") ? strHeight.mid(0, strHeight.length() - 1) : strHeight.mid(0, strHeight.length() - 1) + "." + strHeight.mid(strHeight.length() - 1))
							.arg(wcName);
					}
					else if (name.startsWith("s1flow"))
					{
						imgTitle = QString(tr("%1% Static Pressure Distribution Of Wall(%2)"))
							.arg(strHeight.endsWith("0") ? strHeight.mid(0, strHeight.length() - 1) : strHeight.mid(0, strHeight.length() - 1) + "." + strHeight.mid(strHeight.length() - 1))
							.arg(wcName);
					}
					// pixmap.save(imgFile, "JPG", 100);
					auto *reportData = currentCase->getReportData();
					if (reportData != nullptr)
					{
						reportData->addFlowImage(imgTitle, imgFile);
					}
				}
			}
		}
		// 性能图保存图片
		else if (m_CurrentRenderType == RenderType::PerformRender)
		{
			QString caseDir = Common::C3fdProject::instance()->getCurrentProjectDir();
			QList<QPair<QString, QString>> totalImgs = {};
			QList<QPair<QString, QString>> perStgImgs = {};
			for (auto w : m_PerformCurveWidgets)
			{
				QString name = w->getSeriesTitles().join("-");
				QPixmap pixmap = w->grab();
				QString saveName = "";
				if (name.endsWith("PressureRatio"))
				{
					saveName = "MassFlow-PressureRatio";
				}
				else if (name.endsWith("PressureRatio_Stage"))
				{
					saveName = "Stage_MassFlow-PressureRatio";
				}
				else if (name.endsWith("Efficiency"))
				{
					saveName = "MassFlow-Efficiency";
				}
				else if (name.endsWith("Efficiency_Stage"))
				{
					saveName = "Stage_MassFlow-Efficiency";
				}
				else
				{
					saveName = Common::md5(name);
				}

				pixmap.save(QString("%1/%2.jpg").arg(path).arg(saveName), "JPG");

				// 保存图片用于生成报告
				auto imgFile = QString("%1temp/Performance-%2%3.jpg").arg(caseDir).arg(saveName).arg(time);
				w->saveImage(imgFile, 280, 280);
				if (name.endsWith("_Stage"))
				{
					perStgImgs.push_back(QPair<QString, QString>(translate(saveName), imgFile));
				}
				else
				{
					totalImgs.push_back(QPair<QString, QString>(translate(saveName), imgFile));
				}
			}
			if (currentCase != nullptr)
			{
				auto *reportData = currentCase->getReportData();
				if (reportData != nullptr)
				{
					for (auto i : totalImgs)
					{
						reportData->addPerformanceImage(i.first, i.second);
					}
					for (auto i : perStgImgs)
					{
						reportData->addPerformanceImage(i.first, i.second);
					}
				}
			}
		}
	}

	bool C3fdRenderWindow::clearLayout(bool delChild)
	{
		if (nullptr == m_Layout)
		{
			return true;
		}
		QLayoutItem *child;
		while ((child = m_Layout->takeAt(0)) != 0)
		{
			if (delChild)
			{
				delete child;
				child = nullptr;
			}
		}
		return true;
	}

	bool C3fdRenderWindow::initGeomRenderWidget(bool reset)
	{
		hideAllWidget();
		if (m_GeomRenderWidget == nullptr)
		{
			m_GeomRenderWidget = new C3fdRenderWidget(this);
		}
		else
		{
			if (reset)
			{
				m_GeomRenderWidget->clearAllActor();
				m_GeomRenderWidget->fitView();
			}
			m_GeomRenderWidget->show();
		}
		clearLayout();
		m_Layout->addWidget(m_GeomRenderWidget);
		m_CurrentRenderType = RenderType::GeomRender;
		return true;
	}

	bool C3fdRenderWindow::initMeshRenderWidget(bool reset)
	{
		hideAllWidget();
		if (m_MeshRenderWidgets.size() != 5)
		{
			/*for (auto *w : m_MeshRenderWidgets) {
				if (w != nullptr) {
					delete w;
					w = nullptr;
				}
			}*/
			for (int i = 0; i < 5; ++i)
			{
				m_MeshRenderWidgets.push_back(new C3fdRenderWidget(this));
			}
		}
		else
		{
			for (auto *w : m_MeshRenderWidgets)
			{
				if (reset)
				{
					w->clearAllActor();
				}
				if (w != nullptr)
				{
					w->show();
				}
			}
		}
		auto *splitter1 = new QSplitter(Qt::Vertical, this);
		auto *splitter2 = new QSplitter(Qt::Horizontal, splitter1);
		auto *splitter3 = new QSplitter(Qt::Horizontal, splitter1);

		QList<int> widgetSizes = {};
		widgetSizes << 1000 << 1000 << 1000;
		splitter1->setSizes(widgetSizes);
		splitter2->setSizes(widgetSizes);
		splitter3->setSizes(widgetSizes);

		splitter2->addWidget(m_MeshRenderWidgets.at(0));
		splitter2->addWidget(m_MeshRenderWidgets.at(1));
		splitter3->addWidget(m_MeshRenderWidgets.at(2));
		splitter3->addWidget(m_MeshRenderWidgets.at(3));
		splitter3->addWidget(m_MeshRenderWidgets.at(4));
		splitter1->addWidget(splitter2);
		splitter1->addWidget(splitter3);

		clearLayout();
		m_Layout->addWidget(splitter1);
		m_CurrentRenderType = RenderType::MeshRender;
		return true;
	}

	bool C3fdRenderWindow::initMonitorChartWidget(bool reset)
	{
		hideAllWidget();
		if (m_MonitorCurveWidget == nullptr)
		{
			QStringList newTitles = {
				tr("NPASS"), tr("FMASSI"), tr("FMASSO"), tr("TPRATIO"), tr("EFFISEN"), tr("EFFPOLY") };
			m_MonitorCurveWidget = new C3fdChartWidget(newTitles);
			m_MonitorCurveWidget->enableLegendCheck(true);
			m_MonitorCurveWidget->showCurve(tr("FMASSI"));
		}
		else
		{
			if (reset)
			{
				m_MonitorCurveWidget->clearAllCurve();
			}
			m_MonitorCurveWidget->show();
		}
		clearLayout();
		m_Layout->addWidget(m_MonitorCurveWidget);
		m_CurrentRenderType = RenderType::MonitorRender;
		return true;
	}

	bool C3fdRenderWindow::initPerformChartWidget(bool reset)
	{
		hideAllWidget();
		if (m_PerformCurveWidgets.size() != 4)
		{
			m_PerformCurveWidgets.push_back(new C3fdChartWidget({ tr("Flow(kg/s)"), tr("PressureRatio") }, true));
			m_PerformCurveWidgets.push_back(new C3fdChartWidget({ tr("Flow(kg/s)"), tr("Efficiency") }, true));
			m_PerformCurveWidgets.push_back(new C3fdChartWidget({ tr("Flow(kg/s)"), tr("PressureRatio_Stage") }, true));
			m_PerformCurveWidgets.push_back(new C3fdChartWidget({ tr("Flow(kg/s)"), tr("Efficiency_Stage") }, true));
		}
		else
		{
			for (auto *w : m_PerformCurveWidgets)
			{
				if (reset)
				{
					w->clearAllCurve();
				}
				w->show();
			}
		}
		clearLayout();
		auto *splitter1 = new QSplitter(Qt::Horizontal, this);
		auto *splitter2 = new QSplitter(Qt::Vertical, splitter1);
		auto *splitter3 = new QSplitter(Qt::Vertical, splitter1);
		splitter1->setHandleWidth(0);
		splitter2->setHandleWidth(0);
		splitter3->setHandleWidth(0);
		splitter2->addWidget(m_PerformCurveWidgets.at(0));
		splitter2->addWidget(m_PerformCurveWidgets.at(1));
		splitter3->addWidget(m_PerformCurveWidgets.at(2));
		splitter3->addWidget(m_PerformCurveWidgets.at(3));
		splitter1->addWidget(splitter2);
		splitter1->addWidget(splitter3);

		m_Layout->addWidget(splitter1);

		m_CurrentRenderType = RenderType::PerformRender;
		return true;
	}

	bool C3fdRenderWindow::initPostRendererWidget(bool reset)
	{
		hideAllWidget();
		if (m_PostRenderWidgets.size() != 4)
		{
			Setting::GraphOption *option = Setting::BusAPI::instance()->getGraphOption();
			QColor topcolor = option->getBackgroundTopColor();
			QColor bottomcolor = option->getBackgroundBottomColor();
			QColor meshEdgecolor = option->getMeshEdgeColor();

			auto *vtkWidget1 = new C3fdRenderWidget(this);
			vtkWidget1->setBackGroundColor(topcolor, bottomcolor);
			vtkWidget1->enableFocusSignal(true);
			connect(vtkWidget1, SIGNAL(focusInSig(QWidget *, QString)), m_MainWindow, SIGNAL(postViewFocusInSig(QWidget *, QString)));
			m_PostRenderWidgets.push_back(QPair<QString, QWidget *>("vtk", vtkWidget1));

			auto *vtkWidget2 = new C3fdRenderWidget(this);
			vtkWidget2->setBackGroundColor(topcolor, bottomcolor);
			vtkWidget2->enableFocusSignal(true);
			connect(vtkWidget2, SIGNAL(focusInSig(QWidget *, QString)), m_MainWindow, SIGNAL(postViewFocusInSig(QWidget *, QString)));
			m_PostRenderWidgets.push_back(QPair<QString, QWidget *>("vtk", vtkWidget2));

			auto *chartWidget = new C3fdChartWidget({ "X", "static pressure(Pa)" });
			chartWidget->enableFocusSignal(true);
			connect(chartWidget, SIGNAL(focusInSig(QWidget *, QString)), m_MainWindow, SIGNAL(postViewFocusInSig(QWidget *, QString)));
			m_PostRenderWidgets.push_back(QPair<QString, QWidget *>("qwt", chartWidget));

			auto *vtkWidget3 = new C3fdRenderWidget(this);
			vtkWidget3->setBackGroundColor(topcolor, bottomcolor);
			vtkWidget3->enableFocusSignal(true);
			connect(vtkWidget3, SIGNAL(focusInSig(QWidget *, QString)), m_MainWindow, SIGNAL(postViewFocusInSig(QWidget *, QString)));
			m_PostRenderWidgets.push_back(QPair<QString, QWidget *>("vtk", vtkWidget3));
		}
		else
		{
			for (auto w : m_PostRenderWidgets)
			{
				if (w.second != nullptr)
				{
					if (reset)
					{
						auto *vtk = dynamic_cast<C3fdRenderWidget *>(w.second);
						if (vtk != nullptr)
						{
							vtk->clearAllActor();
						}
						else
						{
							auto *chart = dynamic_cast<C3fdChartWidget *>(w.second);
							if (chart != nullptr)
							{
								chart->clearAllCurve();
							}
						}
					}
					w.second->show();
				}
			}
		}
		clearLayout();
		QSplitter *splitter1 = new QSplitter(Qt::Horizontal, this);
		QSplitter *splitter2 = new QSplitter(Qt::Vertical, splitter1);
		QSplitter *splitter3 = new QSplitter(Qt::Vertical, splitter1);
		// splitter1->setHandleWidth(2);
		// splitter2->setHandleWidth(2);
		// splitter3->setHandleWidth(2);

		splitter2->addWidget(m_PostRenderWidgets.at(0).second);
		splitter2->addWidget(m_PostRenderWidgets.at(2).second);
		splitter3->addWidget(m_PostRenderWidgets.at(1).second);
		splitter3->addWidget(m_PostRenderWidgets.at(3).second);

		splitter1->addWidget(splitter2);
		splitter1->addWidget(splitter3);

		QList<int> widgetSizes;
		widgetSizes << 1000 << 1000;
		splitter1->setSizes(widgetSizes);
		splitter2->setSizes(widgetSizes);
		splitter3->setSizes(widgetSizes);
		m_Layout->addWidget(splitter1);
		m_CurrentRenderType = RenderType::PostRender;
		return true;
	}

	bool C3fdRenderWindow::hideAllWidget()
	{
		if (m_GeomRenderWidget != nullptr)
		{
			m_GeomRenderWidget->hide();
		}
		if (m_MeshRenderWidgets.size() > 0)
		{
			for (auto *widget : m_MeshRenderWidgets)
			{
				if (widget != nullptr)
				{
					widget->hide();
				}
			}
		}
		if (m_PostRenderWidgets.size() > 0)
		{
			for (auto w : m_PostRenderWidgets)
			{
				if (w.second != nullptr)
				{
					w.second->hide();
				}
			}
		}
		if (m_PerformCurveWidgets.size() > 0)
		{
			for (auto *widget : m_PerformCurveWidgets)
			{
				if (widget != nullptr)
				{
					widget->hide();
				}
			}
		}
		if (m_MonitorCurveWidget != nullptr)
		{
			m_MonitorCurveWidget->hide();
		}
		return true;
	}

}
